package com.asiainfo.work.task;

import com.alibaba.fastjson.JSONObject;
import com.asiainfo.work.constant.ProjectEnum;
import com.asiainfo.work.entity.UserMergeCode;
import com.asiainfo.work.service.master.MergeService;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

/**
 * @author: bf
 * @date: 2021/1/4-14:31
 * 定时任务统计git代码合并情况, 并将数据写入user_merge_code表
 */
@Component
@Slf4j
@EnableScheduling
public class GitScheduleTask {

    @Resource
    private RestTemplate restTemplate;

    @Value("${private-token}")
    private String token;

    @Value("${gitLabUlrAndPort}")
    private String gitLabUlrAndPort;

    @Autowired
    private MergeService mergeService;

    private List<Integer> projectList =
            new ArrayList<Integer>(){{add(ProjectEnum.WMSF.getProjectId());add(ProjectEnum.RM.getProjectId());}};

    /**
     * 每天23:00:00 统计当天git代码合并信息,将数据写入 user_merge_code表
     * 1.遍历项目进行统计
     * 2.拉取当天提交合并的代码请求
     * 3.过滤请求, 保留source_branch以feature开头的请求,获取单个请求的mergeId,
     * 4.通过mergeId去查询具体代码合并量
     * 5.将当天提交合并的代码入库
     */
    @Scheduled(cron = "0 0 23 * * ?")
    public void execute() {
        //1.统计项目id(目前只统计 wmsf 和 rm项目)
        String startTime = (String)getTZTime().get("startTime");
        String endTime = (String)getTZTime().get("endTime");
        List<UserMergeCode> userMergeCodeList = new ArrayList<UserMergeCode>();
        for(int i=0; i<projectList.size(); i++){
            List <HashMap<String,Object>> mergeList = new ArrayList<HashMap<String,Object>>();
            int projectId = projectList.get(i);
            RestTemplate restTemplate = new RestTemplate();
            HttpHeaders headers = new HttpHeaders();
            headers.add("PRIVATE-TOKEN", token);
            //2.计算出所有今天合并的代码
            for(int page =1; page<100; page++){
                String url = gitLabUlrAndPort + "/api/v4/projects/"+ projectId +"/merge_requests?state=all"
                        + "&target_branch=develop&created_before="+ endTime +"&created_after="+ startTime +"&page="+ page;
                HttpEntity<String> requestEntity = new HttpEntity<>(null, headers);
                ResponseEntity<Object> resEntity = restTemplate.exchange(url.toString(), HttpMethod.GET, requestEntity,
                        Object.class);
                List <HashMap<String,Object>> lists = (List<HashMap<String,Object>>)resEntity.getBody();
                if(lists.size() > 0){
                    mergeList.addAll((List<HashMap<String,Object>>)resEntity.getBody());
                }else{
                    break;
                }
            }

            //3.过滤source_branch, 保留以 feature开头的
            mergeList.stream().forEach(item->{
                String sourceBranch = (String)item.get("source_branch");
                if(sourceBranch.startsWith("feature")){
                    Map<String,String> author = (HashMap<String,String>)item.get("author");
                    UserMergeCode userMergeCode = new UserMergeCode();
                    //这里做特殊处理(由于禅道的账号和git的不一样) 将account=zhoupeng 写成 zhoupengwh; 将 zhengwei 写成 zhengwei9
                    String account = changeName(author.get("username"));
                    userMergeCode.setAccount(account);
                    userMergeCode.setUserName(author.get("name"));
                    userMergeCode.setProjectId(projectId);
                    userMergeCode.setSourceBranch(sourceBranch);
                    Map<String, String> merged = (HashMap<String,String>)item.get("assignee");
                    if(null != merged){
                        String mergedBy = merged.get("name");
                        userMergeCode.setMergeBy(mergedBy);
                    }
                    try {
                        Date mergedTime = parseTime((String)item.get("created_at"));
                        userMergeCode.setMergeTime(mergedTime);
                        userMergeCode.setCreateTime(new Date());
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    int mergeId = (int)item.get("iid");

                    //4.调用git获取merge比对详情信息的接口, 获取代码合并的添加行数和删除行数
                    String url = gitLabUlrAndPort + "/api/v4/projects/"+ projectId +"/merge_requests/"+ mergeId +"/changes";
                    JSONObject mergeEffect = getMergeEffect(url);
                    if(null != mergeEffect){
                        int addTotal = (int)mergeEffect.get("addTotal");
                        int deleteTotal = (int)mergeEffect.get("deleteTotal");
                        int effectCount = (int)mergeEffect.get("effectCount");
                        userMergeCode.setAddCount(addTotal);
                        userMergeCode.setDeleteCount(deleteTotal);
                        userMergeCode.setEffectCount(effectCount);
                        userMergeCodeList.add(userMergeCode);
                    }
                }
            });
        }

        //5.数据入库
        if(userMergeCodeList.size() > 0){
            mergeService.batchInsert(userMergeCodeList);
        }
    }

    /**
     * 特殊转换
     * 由于禅道的账号和git的不一样 将account=zhoupeng 写成 zhoupengwh; 将 zhengwei 写成 zhengwei9
     */
    public String changeName(String beforeName){
        String afterName = beforeName;
        switch (beforeName){
            case "zhoupeng" :
                afterName = "zhoupengwh";
                break;
            case "zhengwei" :
                afterName = "zhengwei9";
                break;
        }
        return afterName;
    }


    /**
     * 获取当天范围内的TZ类型的时间
     * @return
     */
    public JSONObject getTZTime(){
        Calendar cal=Calendar.getInstance();
        cal.add(Calendar.DATE,-1);
        Date d=cal.getTime();
        SimpleDateFormat sp=new SimpleDateFormat("yyyy-MM-dd");
        String yesterday =sp.format(d);
        String startTime = yesterday + "T16:00:00Z";
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        String endTime = df.format(new Date()) + "T" + "15:59:59Z";
        JSONObject json = new JSONObject();
        json.put("startTime", startTime);
        json.put("endTime",endTime);
        return json;
    }

    public static Date parseTime(String utcTime) throws ParseException {
        String[] ts = utcTime.split("T");
        String[] split = ts[1].split("\\.");
        String formatTime = ts[0] + " " + split[0];
        DateFormat fmt =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = fmt.parse(formatTime);
        return date;
    }

    /**
     * 获取合并代码时影响代码的行数
     * @param url 请求的utl
     * @return 返回代码合并添加的行数, 删除的行数, 影响的行数
     */
    public JSONObject getMergeEffect(String url){
        HttpHeaders headers = new HttpHeaders();
        headers.add("PRIVATE-TOKEN", token);
        HttpEntity<String> requestEntity = new HttpEntity<>(null, headers);
        //如果git合并代码失败, 我们需要跳过这行统计   pipeline failed
        int addTotal = 0;
        int deleteTotal = 0;
        try {
            ResponseEntity<Object> mergeEntity = restTemplate.exchange(url.toString(), HttpMethod.GET,requestEntity,Object.class);
            Map<String,Object> merge = (HashMap<String,Object>)mergeEntity.getBody();
            List<Map<String,Object>> changes = (List<Map<String,Object>>)merge.get("changes");
            for(int p =0; p<changes.size();p++){
                Map map = (Map)changes.get(p);
                String diff = (String)map.get("diff");
                Map<String, Object> mapDiff = statisticsMergeCode(diff);
                int add = (int)mapDiff.get("add");
                int delete = (int)mapDiff.get("delete");
                addTotal += add;
                deleteTotal += delete;
            }
            JSONObject json = new JSONObject();
            json.put("addTotal", addTotal);
            json.put("deleteTotal", deleteTotal);
            json.put("effectCount", deleteTotal + addTotal);
            return json;
        }catch (Exception e){
            log.warn("git发起代码merge有问题 pipeline failed , 查看url是 url={}", url);
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 计算当前数据中减少的代码行和添加的代码行数
     * @param msg  待解析的数据
     * @return json   add: 添加的代码行,   delete: 减少的代码行
     */
    public Map<String, Object> statisticsMergeCode(String msg){
        JSONObject json = new JSONObject();
        int deleteRow = 0;
        int addRow = 0;
        String[] split = msg.split("\\n");
        for(int i=0;i<split.length;i++){
            String obj = split[i];
            if(obj.startsWith("-")){
                deleteRow ++;
            }else if(obj.startsWith("+")){
                addRow ++;
            }
        }
        json.put("add",addRow);
        json.put("delete",deleteRow);
        return json;
    }

}
